package org.example.volunteerend.service.impl;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import org.example.volunteerend.dto.AdminInvitationRequest;
import org.example.volunteerend.dto.AdminProjectReviewRequest;
import org.example.volunteerend.dto.PageResponse;
import org.example.volunteerend.dto.ProjectCategoryRequest;
import org.example.volunteerend.entity.AdminInvitationCode;
import org.example.volunteerend.entity.AdminOperationLog;
import org.example.volunteerend.entity.ProjectCategory;
import org.example.volunteerend.entity.VolunteerProject;
import org.example.volunteerend.mapper.AdminInvitationCodeMapper;
import org.example.volunteerend.mapper.AdminOperationLogMapper;
import org.example.volunteerend.mapper.ProjectCategoryMapper;
import org.example.volunteerend.mapper.UserMapper;
import org.example.volunteerend.mapper.VolunteerProjectMapper;
import org.example.volunteerend.service.AdminService;
import org.example.volunteerend.service.ProjectService;
import org.example.volunteerend.utils.AliOssUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import jakarta.servlet.http.HttpServletRequest;

@Service
public class AdminServiceImpl implements AdminService {

    private final AdminInvitationCodeMapper adminInvitationCodeMapper;
    private final AdminOperationLogMapper adminOperationLogMapper;
    private final UserMapper userMapper;
    private final VolunteerProjectMapper volunteerProjectMapper;
    private final ProjectService projectService;
    private final JdbcTemplate jdbcTemplate;
    private final ProjectCategoryMapper projectCategoryMapper;

    @Autowired
    public AdminServiceImpl(
            AdminInvitationCodeMapper adminInvitationCodeMapper,
            AdminOperationLogMapper adminOperationLogMapper,
            UserMapper userMapper,
            VolunteerProjectMapper volunteerProjectMapper,
            ProjectService projectService,
            JdbcTemplate jdbcTemplate,
            ProjectCategoryMapper projectCategoryMapper) {
        this.adminInvitationCodeMapper = adminInvitationCodeMapper;
        this.adminOperationLogMapper = adminOperationLogMapper;
        this.userMapper = userMapper;
        this.volunteerProjectMapper = volunteerProjectMapper;
        this.projectService = projectService;
        this.jdbcTemplate = jdbcTemplate;
        this.projectCategoryMapper = projectCategoryMapper;
    }

    @Override
    @Transactional
    public Map<String, Object> generateInvitationCode(AdminInvitationRequest request) {
        // 验证创建者是否是管理员
        if (!isAdmin(request.getCreated_by())) {
            throw new IllegalArgumentException("只有管理员才能生成邀请码");
        }
        
        // 生成随机邀请码
        String invitationCode = generateRandomCode();
        
        // 创建邀请码记录
        AdminInvitationCode code = new AdminInvitationCode();
        code.setInvitationCode(invitationCode);
        code.setCreatedBy(request.getCreated_by());
        code.setIsUsed(false);
        
        // 保存到数据库
        adminInvitationCodeMapper.insert(code);
        
        // 返回结果
        Map<String, Object> result = new HashMap<>();
        result.put("code_id", code.getCodeId());
        result.put("invitation_code", code.getInvitationCode());
        
        return result;
    }
    
    @Override
    public PageResponse<AdminOperationLog> getOperationLogs(
            Integer adminId,
            LocalDateTime startTime,
            LocalDateTime endTime,
            String operationType,
            Integer page,
            Integer pageSize) {
        
        // 设置默认值
        if (page == null || page < 1) {
            page = 1;
        }
        if (pageSize == null || pageSize < 1) {
            pageSize = 10;
        }
        
        // 计算偏移量
        int offset = (page - 1) * pageSize;
        
        // 查询日志列表
        List<AdminOperationLog> logs = adminOperationLogMapper.findAdminOperationLogs(
                adminId, startTime, endTime, operationType, offset, pageSize);
        
        // 统计总数
        int total = adminOperationLogMapper.countAdminOperationLogs(
                adminId, startTime, endTime, operationType);
        
        return new PageResponse<>(logs, total, page, pageSize);
    }
    
    @Override
    @Transactional
    public Map<String, Object> reviewProject(Integer projectId, AdminProjectReviewRequest request) {
        // 验证管理员权限
        if (!isAdmin(request.getAdmin_id())) {
            throw new IllegalArgumentException("只有管理员才能审核项目");
        }
        
        // 检查项目是否存在
        VolunteerProject project = volunteerProjectMapper.findById(projectId);
        if (project == null) {
            throw new IllegalArgumentException("项目不存在");
        }
        
        // 验证状态是否有效
        if (!isValidStatus(request.getStatus())) {
            throw new IllegalArgumentException("无效的项目状态");
        }
        
        // 更新项目状态
        projectService.updateProjectStatus(projectId, request.getStatus());
        
        // 更新项目管理员ID
        jdbcTemplate.update(
                "UPDATE volunteer_projects SET admin_id = ? WHERE project_id = ?", 
                request.getAdmin_id(), projectId);
        
        // 返回结果
        Map<String, Object> result = new HashMap<>();
        result.put("project_id", projectId);
        result.put("status", request.getStatus());
        
        return result;
    }
    
    @Override
    public void logAdminOperation(Integer adminId, String operationType, String operationDescription, HttpServletRequest request) {
        // 创建日志记录
        AdminOperationLog log = new AdminOperationLog();
        log.setAdminId(adminId);
        log.setOperationType(operationType);
        log.setOperationDescription(operationDescription);
        log.setIpAddress(getClientIp(request));
        
        // 保存到数据库
        adminOperationLogMapper.insert(log);
    }
    
    @Override
    public Map<String, Object> getStatistics(LocalDate startDate, LocalDate endDate) {
        // 设置默认值：如果开始日期为空，则设置为30天前
        if (startDate == null) {
            startDate = LocalDate.now().minusDays(30);
        }
        
        // 如果结束日期为空，则设置为今天
        if (endDate == null) {
            endDate = LocalDate.now();
        }
        
        // 确保开始日期不晚于结束日期
        if (startDate.isAfter(endDate)) {
            throw new IllegalArgumentException("开始日期不能晚于结束日期");
        }
        
        Map<String, Object> result = new HashMap<>();
        
        // 1. 用户统计
        Map<String, Object> userStats = getUserStatistics(startDate, endDate);
        result.put("user_stats", userStats);
        
        // 2. 项目统计
        Map<String, Object> projectStats = getProjectStatistics();
        result.put("project_stats", projectStats);
        
        // 3. 服务统计
        Map<String, Object> serviceStats = getServiceStatistics();
        result.put("service_stats", serviceStats);
        
        // 4. 分类分布
        List<Map<String, Object>> categoryDistribution = getCategoryDistribution();
        result.put("category_distribution", categoryDistribution);
        
        // 5. 每日趋势
        List<Map<String, Object>> dailyTrend = getDailyTrend(startDate, endDate);
        result.put("daily_trend", dailyTrend);
        
        return result;
    }
    
    @Override
    @Transactional
    public ProjectCategory addProjectCategory(ProjectCategoryRequest request) {
        // 验证分类名称不能为空
        if (request.getCategoryName() == null || request.getCategoryName().trim().isEmpty()) {
            throw new IllegalArgumentException("分类名称不能为空");
        }
        
        // 检查分类名称是否已存在
        ProjectCategory existingCategory = projectCategoryMapper.findByCategoryName(request.getCategoryName());
        if (existingCategory != null) {
            throw new IllegalArgumentException("分类名称已存在");
        }
        
        // 创建新的分类对象
        ProjectCategory category = new ProjectCategory();
        category.setCategoryName(request.getCategoryName());
        category.setDescription(request.getDescription());
        category.setIconUrl(request.getIconUrl());
        
        // 保存到数据库
        projectCategoryMapper.insert(category);
        
        return category;
    }
    
    @Override
    public Map<String, String> updateCategoryIcon(Integer categoryId, MultipartFile iconFile) throws Exception {
        // 验证分类是否存在
        ProjectCategory category = projectCategoryMapper.findById(categoryId);
        if (category == null) {
            throw new IllegalArgumentException("分类不存在");
        }
        
        // 验证文件是否为空
        if (iconFile == null || iconFile.isEmpty()) {
            throw new IllegalArgumentException("图标文件不能为空");
        }
        
        // 验证文件大小
        if (iconFile.getSize() > 2 * 1024 * 1024) { // 2MB
            throw new IllegalArgumentException("图标文件大小不能超过2MB");
        }
        
        // 验证文件类型
        String originalFilename = iconFile.getOriginalFilename();
        if (originalFilename == null) {
            throw new IllegalArgumentException("文件名不能为空");
        }
        
        String fileExtension = getFileExtension(originalFilename);
        if (!isImageExtension(fileExtension)) {
            throw new IllegalArgumentException("只支持图片格式文件（jpg、jpeg、png、gif）");
        }
        
        // 生成唯一文件名
        String filename = "uploads/categories/" + category.getCategoryName().replaceAll("\\s+", "_").toLowerCase() 
                + "_" + System.currentTimeMillis() + fileExtension;
        
        // 上传到阿里云OSS
        String iconUrl = AliOssUtil.uploadFile(filename, iconFile.getInputStream());
        
        // 更新数据库
        projectCategoryMapper.updateIconUrl(categoryId, iconUrl);
        
        // 返回结果
        Map<String, String> result = new HashMap<>();
        result.put("new_icon_url", iconUrl);
        
        return result;
    }
    
    /**
     * 获取文件扩展名
     */
    private String getFileExtension(String filename) {
        int lastDotIndex = filename.lastIndexOf(".");
        return (lastDotIndex == -1) ? "" : filename.substring(lastDotIndex);
    }
    
    /**
     * 判断是否为图片扩展名
     */
    private boolean isImageExtension(String extension) {
        extension = extension.toLowerCase();
        return extension.equals(".jpg") || extension.equals(".jpeg") 
                || extension.equals(".png") || extension.equals(".gif");
    }
    
    // 辅助方法：验证用户是否是管理员
    private boolean isAdmin(Integer userId) {
        String sql = "SELECT is_admin FROM users WHERE user_id = ?";
        Boolean isAdmin = jdbcTemplate.queryForObject(sql, Boolean.class, userId);
        return isAdmin != null && isAdmin;
    }
    
    // 辅助方法：生成随机邀请码
    private String generateRandomCode() {
        return UUID.randomUUID().toString().substring(0, 6).toUpperCase();
    }
    
    // 辅助方法：验证项目状态是否有效
    private boolean isValidStatus(String status) {
        return "招募中".equals(status) || "进行中".equals(status) || 
               "已完成".equals(status) || "已取消".equals(status);
    }
    
    // 辅助方法：获取客户端IP地址
    private String getClientIp(HttpServletRequest request) {
        String ip = request.getHeader("X-Forwarded-For");
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }
    
    // 辅助方法：获取用户统计
    private Map<String, Object> getUserStatistics(LocalDate startDate, LocalDate endDate) {
        // 总用户数
        Integer totalUsers = jdbcTemplate.queryForObject(
                "SELECT COUNT(*) FROM users", Integer.class);
        
        // 新增用户数
        Integer newUsers = jdbcTemplate.queryForObject(
                "SELECT COUNT(*) FROM users WHERE DATE(register_time) BETWEEN ? AND ?",
                Integer.class, startDate, endDate);
        
        // 活跃用户数（有服务记录或评论的用户）
        Integer activeUsers = jdbcTemplate.queryForObject(
                "SELECT COUNT(DISTINCT user_id) FROM (" +
                "  SELECT user_id FROM service_records WHERE DATE(service_date) BETWEEN ? AND ? " +
                "  UNION " +
                "  SELECT user_id FROM community_comments WHERE DATE(create_time) BETWEEN ? AND ? " +
                ") AS active_users",
                Integer.class, startDate, endDate, startDate, endDate);
        
        Map<String, Object> userStats = new HashMap<>();
        userStats.put("total_users", totalUsers);
        userStats.put("new_users", newUsers);
        userStats.put("active_users", activeUsers);
        
        return userStats;
    }
    
    // 辅助方法：获取项目统计
    private Map<String, Object> getProjectStatistics() {
        // 总项目数
        Integer totalProjects = jdbcTemplate.queryForObject(
                "SELECT COUNT(*) FROM volunteer_projects", Integer.class);
        
        // 招募中项目数
        Integer recruitingProjects = jdbcTemplate.queryForObject(
                "SELECT COUNT(*) FROM volunteer_projects WHERE status = '招募中'", Integer.class);
        
        // 进行中项目数
        Integer ongoingProjects = jdbcTemplate.queryForObject(
                "SELECT COUNT(*) FROM volunteer_projects WHERE status = '进行中'", Integer.class);
        
        // 已完成项目数
        Integer completedProjects = jdbcTemplate.queryForObject(
                "SELECT COUNT(*) FROM volunteer_projects WHERE status = '已完成'", Integer.class);
        
        // 已取消项目数
        Integer canceledProjects = jdbcTemplate.queryForObject(
                "SELECT COUNT(*) FROM volunteer_projects WHERE status = '已取消'", Integer.class);
        
        Map<String, Object> projectStats = new HashMap<>();
        projectStats.put("total_projects", totalProjects);
        projectStats.put("recruiting_projects", recruitingProjects);
        projectStats.put("ongoing_projects", ongoingProjects);
        projectStats.put("completed_projects", completedProjects);
        projectStats.put("canceled_projects", canceledProjects);
        
        return projectStats;
    }
    
    // 辅助方法：获取服务统计
    private Map<String, Object> getServiceStatistics() {
        // 总服务时长
        BigDecimal totalHours = jdbcTemplate.queryForObject(
                "SELECT COALESCE(SUM(service_hours), 0) FROM service_records", BigDecimal.class);
        
        // 总报名人次
        Integer totalRegistrations = jdbcTemplate.queryForObject(
                "SELECT COUNT(*) FROM volunteer_registrations", Integer.class);
        
        // 计算人均服务时长
        BigDecimal avgHoursPerUser = BigDecimal.ZERO;
        Integer totalUsersWithService = jdbcTemplate.queryForObject(
                "SELECT COUNT(DISTINCT user_id) FROM service_records", Integer.class);
        
        if (totalUsersWithService != null && totalUsersWithService > 0 && totalHours != null) {
            avgHoursPerUser = totalHours.divide(new BigDecimal(totalUsersWithService), 2, RoundingMode.HALF_UP);
        }
        
        Map<String, Object> serviceStats = new HashMap<>();
        serviceStats.put("total_hours", totalHours);
        serviceStats.put("total_registrations", totalRegistrations);
        serviceStats.put("avg_hours_per_user", avgHoursPerUser);
        
        return serviceStats;
    }
    
    // 辅助方法：获取分类分布
    private List<Map<String, Object>> getCategoryDistribution() {
        String sql = "SELECT c.category_id, c.category_name, COUNT(pcm.project_id) as project_count " +
                     "FROM project_categories c " +
                     "LEFT JOIN project_category_mapping pcm ON c.category_id = pcm.category_id " +
                     "GROUP BY c.category_id, c.category_name";
        
        List<Map<String, Object>> result = jdbcTemplate.queryForList(sql);
        
        // 计算总项目数
        int totalProjects = result.stream()
                .mapToInt(item -> ((Number) item.get("project_count")).intValue())
                .sum();
        
        // 计算每个分类的百分比
        if (totalProjects > 0) {
            for (Map<String, Object> item : result) {
                int projectCount = ((Number) item.get("project_count")).intValue();
                double percentage = (double) projectCount / totalProjects * 100;
                item.put("percentage", Math.round(percentage * 100) / 100.0); // 保留两位小数
            }
        }
        
        return result;
    }
    
    // 辅助方法：获取每日趋势
    private List<Map<String, Object>> getDailyTrend(LocalDate startDate, LocalDate endDate) {
        List<Map<String, Object>> result = new ArrayList<>();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        
        // 生成日期区间内的每一天
        long daysBetween = ChronoUnit.DAYS.between(startDate, endDate) + 1;
        if (daysBetween > 60) { // 如果超过60天，就按周或月聚合，这里简化处理
            daysBetween = 60;
        }
        
        for (int i = 0; i < daysBetween; i++) {
            LocalDate date = startDate.plusDays(i);
            String dateStr = date.format(formatter);
            
            // 查询每日新增用户
            Integer newUsers = jdbcTemplate.queryForObject(
                    "SELECT COUNT(*) FROM users WHERE DATE(register_time) = ?",
                    Integer.class, date);
            
            // 查询每日新增项目
            Integer newProjects = jdbcTemplate.queryForObject(
                    "SELECT COUNT(*) FROM volunteer_projects WHERE DATE(start_time) = ?",
                    Integer.class, date);
            
            // 查询每日服务时长
            BigDecimal serviceHours = jdbcTemplate.queryForObject(
                    "SELECT COALESCE(SUM(service_hours), 0) FROM service_records WHERE service_date = ?",
                    BigDecimal.class, date);
            
            Map<String, Object> dayData = new HashMap<>();
            dayData.put("date", dateStr);
            dayData.put("new_users", newUsers);
            dayData.put("new_projects", newProjects);
            dayData.put("service_hours", serviceHours);
            
            result.add(dayData);
        }
        
        return result;
    }
} 